﻿using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using MvvmHelpers;
using MvvmHelpers.Commands;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows.Input;
using TabbedTemplate.Models;
using TabbedTemplate.Services;
using Xamarin.Forms.Extended;

namespace TabbedTemplate.ViewModels
{
    public class IndexPageViewModel : ViewModelBase, INotifyPropertyChanged
    {
        /// <summary>
        /// 店铺存储服务。
        /// </summary>
        private IStoreService _storeService;

        /// <summary>
        /// 导航服务。
        /// </summary>
        private IPunchNavigationService _punchNavigationService;

        /// <summary>
        /// 偏好存储服务。
        /// </summary>
        private IPreferenceStorage _preferenceStorage;

        /// <summary>
        /// 北京存储服务
        /// </summary>
        private IBeijingCacheService _beijingCacheService;


        private ILocationService _locationService;

        /// <summary>
        /// 只读。
        /// </summary>
        private InfiniteScrollCollection<Store> _storeCollection;

        public InfiniteScrollCollection<Store> StoreCollection
        {
            get => _storeCollection;
            set => Set(nameof(StoreCollection), ref _storeCollection, value);
        }

        public InfiniteScrollCollection<Store> QueryStoreCollection { get; }

        public ObservableRangeCollection<Store> _storesFromWeb =
            new ObservableRangeCollection<Store>();

        /// <summary>
        /// 从web获取的店铺数据
        /// </summary>
        public ObservableRangeCollection<Store> StoresFromWeb
        {
            get => _storesFromWeb;
            set => Set(nameof(StoresFromWeb), ref _storesFromWeb, value);
        }


        public string Title { get; set; }

        public double Lat { get; set; }

        public int PageNum { get; set; }


        public string Input { get; set; }


        /// <summary>
        /// 依赖注入
        /// </summary>
        /// <param name="storeService">店铺服务。</param>
        public IndexPageViewModel(IStoreService storeService,
            IPunchNavigationService punchNavigationService,
            IPreferenceStorage preferenceStorage,
            IBeijingCacheService beijingCacheService,
            ILocationService locationService)
        {
            Title = "东北大学";
            _storeService = storeService;
            _punchNavigationService = punchNavigationService;
            _preferenceStorage = preferenceStorage;
            StoreCollection = new InfiniteScrollCollection<Store>();
            QueryStoreCollection = new InfiniteScrollCollection<Store>();
            _beijingCacheService = beijingCacheService;
            _locationService = locationService;
            Input = "";
            _preferenceStorage.Set("newQuery", true);
        }

        /// <summary>
        /// 正在载入。
        /// </summary>
        public const string Loading = "正在载入";

        /// <summary>
        /// 没有满足条件的结果。
        /// </summary>
        public const string NoResult = "没有满足条件的结果";

        /// <summary>
        /// 没有更多结果。
        /// </summary>
        public const string NoMoreResult = "没有更多结果";

        //******** 绑定属性

        /// <summary>
        /// 标签。
        /// </summary>
        public Tag Tag
        {
            get => _tag;
            set => Set(nameof(Tag), ref _tag, value);
        }

        /// <summary>
        /// 标签。
        /// </summary>
        private Tag _tag;

        /// <summary>
        /// 加载状态。
        /// </summary>
        public string TagCnName;

        public string Status
        {
            get => _status;
            set => Set(nameof(Status), ref _status, value);
        }

        /// <summary>
        /// 加载状态。
        /// </summary>
        private string _status;


        // ******** 私有变量

        /// <summary>
        /// 能否加载更多诗词。
        /// </summary>
        public bool CanLoadMore;

        /// <summary>
        /// 是否为新查询。
        /// </summary>
        private bool _newQuery;

        private List<string> _testList;

        public List<string> TestList
        {
            get => _testList;
            set => Set(nameof(TestList), ref _testList, value);
        }

        /// <summary>
        /// 从web中获取店铺命令。
        /// </summary>
        private RelayCommand _storesAppearingCommand;

        public RelayCommand GetStoresFromWebCommand =>
            _storesAppearingCommand ??= new RelayCommand(async () =>
                await GetStoresFromWebCommandFunctionAsync());

        public async Task GetStoresFromWebCommandFunctionAsync()
        {
            _newQuery = _preferenceStorage.Get("newQuery", true);
            if (!_newQuery)
            {
                return;
            }

            PageNum = 0;
            StoreCollection.Clear();
            StoreCollection.OnCanLoadMore = () => CanLoadMore;
            StoreCollection.OnLoadMore = async () =>
            {
                Status = Loading;
                NotifyPropertyChanged("Status");
                TagCnName = Tag.CnName;
                List<Store> stores;
                //MaxValue
                if (_preferenceStorage.Get("Latitude", double.MaxValue) ==
                    double.MaxValue)
                {
                    if (!_beijingCacheService.BeijingInitialized())
                    {
                        await _beijingCacheService.InitializeBeijingAsync();
                    }

                    stores =
                        (List<Store>)await _beijingCacheService
                            .GetBeijingStoreByTagAsync("美食;" + TagCnName,
                                StoreCollection.Count, StoreService.PageSize);

                    //未开启定位，距离显示的是到故宫的距离。
                    if (_preferenceStorage.Get("isLocationOpened", "true") ==
                        "false")
                    {
                        foreach (var store in stores)
                        {
                            store.Distance = Convert.ToString(
                                Convert.ToDouble(store.Distance) / 1000,
                                CultureInfo.InvariantCulture);
                        }
                    }
                    //开启定位，北京到现在的距离。
                    else
                    {
                        var currentLocationLatitude =
                            _preferenceStorage.Get("currentLocationLatitude",
                                39.915);
                        var currentLocationLongitude =
                            _preferenceStorage.Get("currentLocationLongitude",
                                116.404);
                        var currentPosition = new Position
                        {
                            Latitude = currentLocationLatitude,
                            Longitude = currentLocationLongitude
                        };
                        foreach (var store in stores)
                        {
                            store.Distance = Convert.ToString(
                                Convert.ToDouble(
                                    _locationService.CalculateDistance(
                                        currentPosition,
                                        new Position
                                        {
                                            Latitude = 39.915,
                                            Longitude = 116.404
                                        })) + Convert.ToDouble(store.Distance) /
                                1000, CultureInfo.InvariantCulture);
                        }
                    }
                }
                else
                {
                    //double.minValue 是自己切换城市后的标识(非北京市，北京市为MaxValue)
                    if (_preferenceStorage.Get("Latitude", Double.MaxValue) ==
                        double.MinValue)
                    {
                        var cityName = _preferenceStorage.Get("City", "北京市");
                        stores =
                            (List<Store>)await _storeService
                                .SearchStoresByRegionFromWebAsync(
                                    "美食;" + TagCnName, cityName,
                                    StoreCollection.Count /
                                    StoreService.PageSize);
                    }
                    else
                    {
                        //自动定位的情况
                        stores = await _storeService.GetStoresFromWebAsync(Tag,
                            _preferenceStorage.Get("Latitude", 39.915),
                            _preferenceStorage.Get("Longitude", 116.404),
                            100000,
                            StoreCollection.Count / StoreService.PageSize);
                    }
                }

                if (stores.Count < StoreService.PageSize)
                {
                    CanLoadMore = false;
                    Status = NoMoreResult;
                }
                else
                {
                    Status = "";
                }

                if (StoreCollection.Count == 0 && stores.Count == 0)
                {
                    Status = NoResult;
                }

                NotifyPropertyChanged("Tag");
                NotifyPropertyChanged("Status");
                return stores;
            };
            CanLoadMore = true;
            await StoreCollection.LoadMoreAsync();
            _newQuery = false;
        }

        private RelayCommand<Store> _storeTappedCommand;

        public RelayCommand<Store> StoreTappedCommand =>
            _storeTappedCommand ??= new RelayCommand<Store>(async store =>
                await StoreTappedCommandFunction(store));

        public async Task StoreTappedCommandFunction(Store store) =>
            await _punchNavigationService.NavigateToAsync(
                ContentNavigationConstant.StorePunchesPage, store);


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void NotifyPropertyChanged(
            [CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(propertyName));
        }

        public ICommand PerformSearch =>
            new Command<string>(async (string query) =>
                await PerformSearchFunction(query));

        public async Task PerformSearchFunction(string query)
        {
            ClassifySearchParameter classifySearchParameter =
                new ClassifySearchParameter { Tag = TagCnName, Input = query };
            await _punchNavigationService.NavigateToAsync(
                ContentNavigationConstant.QueryResultPage,
                classifySearchParameter);
            Input = "";
            NotifyPropertyChanged("Input");
        }

        private List<Store> searchResults;

        public List<Store> SearchResults
        {
            get { return searchResults; }
            set
            {
                searchResults = value;
                NotifyPropertyChanged();
            }
        }
    }
}
